using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using WozLib.UI.Ink;
using WozLib.WozObjects;
using System.Windows;
using WozLib.UI.Ink.SketchElements;
using WozLib.UI.Ink.SketchCommands;
using WozLib.UI.Ink.SketchProperties;
using WozLib.UI.Ink.SketchObjects;
using System.Windows.Ink;
using WozLib.Net;
using WozLib.WozCommands;
using System.Diagnostics;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Media;

namespace WozLib.UI.Ink
{
  public class ReplacementPad : WozScreen
  {
    public ReplacementPad()
      : base(80, 40, "text")
    {
      ServerObjectRegistry.RegisterObject(this);

      // add a SketchText control
      Rect rect = new Rect(0, 0, 80, 40);
      SketchText wozText = new SketchText(rect, this.WozObjectRegistry);
      wozText.SetProperty(new StringSketchProperty("Aaaa", WozPropertyType.Text));
      this.Children.Add(wozText);

      //// create CreateCommand
      //CreateSketchCommand wozClientCreateCommand = new CreateSketchCommand(wozText.GetWozObject());

      //// push creation command
      //creationCommand = (wozClientCreateCommand);

      //wozText.TextChanged += new TextChangedEventHandler(wozText_TextChanged);
    }

    public ReplacementPad(ButtonSketchObject buttonSketchObject)
      : this(buttonSketchObject, "button clicked")
    {
    }

    public ReplacementPad(StrokeSketchObject strokeSketchObject)
      : this(strokeSketchObject, "gesture")
    {
    }

    public ReplacementPad(SketchObject sketchObject, string description)
      : base(80, 40, description)
    {
      ServerObjectRegistry.RegisterObject(this);

      List<UIElement> createdUies = new List<UIElement>();
      List<SketchObject> createdObjects = new List<SketchObject>();
      StrokeCollection createdStrokes = new StrokeCollection();

      ISketchObject iWozObject = sketchObject.GetNewIWozObject(this.WozObjectRegistry);

      if (iWozObject is Stroke)
      {
        this.Strokes.Add(iWozObject as Stroke);
        createdStrokes.Add(iWozObject as Stroke);
      }
      else if (iWozObject is UIElement)
      {
        this.Children.Add(iWozObject as UIElement);
        createdUies.Add(iWozObject as UIElement);
      }

      // don't use original WozObject cause it has a bad ID
      createdObjects.Add(iWozObject.GetWozObject());

      // shift left
      // shift up
      double minLeft = double.MaxValue;
      double minTop = double.MaxValue;
      foreach (UIElement uie in this.Children)
      {
        if ((double)uie.GetValue(InkCanvas.LeftProperty) < minLeft)
        {
          minLeft = (double)uie.GetValue(InkCanvas.LeftProperty);
        }

        if ((double)uie.GetValue(InkCanvas.TopProperty) < minTop)
        {
          minTop = (double)uie.GetValue(InkCanvas.TopProperty);
        }
      }
      foreach (Stroke stroke in this.Strokes)
      {
        if (stroke.GetBounds().Left < minLeft)
        {
          minLeft = stroke.GetBounds().Left;
        }

        if (stroke.GetBounds().Top < minTop)
        {
          minTop = stroke.GetBounds().Top;
        }
      }

      if (minLeft < double.MaxValue && minTop < double.MaxValue)
      {
        foreach (UIElement uie in this.Children)
        {

          if (uie is ISketchObject)
          {
            //ISketchObject iSketchObject = uie as ISketchObject;

            //SketchProperty sketchProperty = iSketchObject.GetProperty(WozPropertyType.RectGeometry);

            //if (sketchProperty is RectGeometrySketchProperty)
            //{
            //  RectGeometrySketchProperty rectGeometrySketchProperty = sketchProperty as RectGeometrySketchProperty;

            //  iSketchObject.SetProperty(new RectGeometrySketchProperty(
            //    new Rect(rectGeometrySketchProperty.Rect.Left - minLeft,
            //    rectGeometrySketchProperty.Top - minTop, rectGeometrySketchProperty.Width,
            //    rectGeometrySketchProperty.Height), WozPropertyType.RectGeometry));
            //}

            uie.SetValue(InkCanvas.LeftProperty,
            (double)uie.GetValue(InkCanvas.LeftProperty) - minLeft);

            uie.SetValue(InkCanvas.TopProperty,
              (double)uie.GetValue(InkCanvas.TopProperty) - minTop);

            (uie as ISketchObject).SyncProperties();
          }
        }

        Matrix inkTransform = new Matrix();
        inkTransform.Translate(-minLeft, -minTop);

        foreach (Stroke stroke in this.Strokes)
        {
          if (stroke is ISketchObject)
          {
            stroke.Transform(inkTransform, false);
            (stroke as ISketchObject).SyncProperties();
          }
        }
      }

      // measure
      double maxWidth = 0;
      double maxHeight = 0;
      foreach (UIElement uie in this.Children)
      {
        // need to make them figure out how big they are
        uie.Measure(new Size(double.MaxValue, double.MaxValue));

        if ((double)uie.GetValue(InkCanvas.LeftProperty) >= 0 &&
          uie.DesiredSize.Width + (double)uie.GetValue(InkCanvas.LeftProperty) > maxWidth)
        {
          maxWidth = uie.DesiredSize.Width + (double)uie.GetValue(InkCanvas.LeftProperty);
        }

        if ((double)uie.GetValue(InkCanvas.TopProperty) >= 0 &&
          uie.DesiredSize.Height + (double)uie.GetValue(InkCanvas.TopProperty) > maxHeight)
        {
          maxHeight = uie.DesiredSize.Height + (double)uie.GetValue(InkCanvas.TopProperty);
        }
      }
      foreach (Stroke stroke in this.Strokes)
      {
        Rect bounds = stroke.GetBounds();

        if (bounds.Right > maxWidth)
        {
          maxWidth = bounds.Right;
        }

        if (bounds.Bottom > maxHeight)
        {
          maxHeight = bounds.Bottom;
        }
      }

      // clip
      if (maxWidth > 0 && maxHeight > 0)
      {
        this.Width = maxWidth;
        this.Height = maxHeight;
      }
    }

    public ReplacementPad(bool isFromClipboard)
      : base(80, 40, "")
    {
      ServerObjectRegistry.RegisterObject(this);

      if (isFromClipboard)
      {
        //this.Loaded += new RoutedEventHandler(FromClipboard_Loaded);

        try
        {
          List<UIElement> createdUies = new List<UIElement>();
          List<SketchObject> createdObjects = new List<SketchObject>();
          StrokeCollection createdStrokes = new StrokeCollection();

          // try to paste in WozObjectsXML
          if (Clipboard.ContainsData("WozObjectsXML"))
          {
            try
            {
              object o = Clipboard.GetData("WozObjectsXML");

              if (o is string)
              {
                string xml = o as string;

                // time to deserialize the XmlObjects
                // remember to register them as new objects (new wozIDs!)

                XmlSerializer mySerializer = new XmlSerializer(typeof(List<SketchObject>));

                StringReader sr = new StringReader(xml);

                object oUnserialized = mySerializer.Deserialize(sr);

                sr.Close();

                if (oUnserialized is List<SketchObject>)
                {
                  List<SketchObject> unserialized = oUnserialized as List<SketchObject>;

                  foreach (SketchObject wozObject in unserialized)
                  {
                    ISketchObject iWozObject = wozObject.GetNewIWozObject(this.WozObjectRegistry);

                    if (iWozObject is Stroke)
                    {
                      this.Strokes.Add(iWozObject as Stroke);
                      createdStrokes.Add(iWozObject as Stroke);
                    }
                    else if (iWozObject is UIElement)
                    {
                      this.Children.Add(iWozObject as UIElement);
                      createdUies.Add(iWozObject as UIElement);
                    }

                    // don't use original WozObject cause it has a bad ID
                    createdObjects.Add(iWozObject.GetWozObject());
                  }
                }
              }
            }
            catch (Exception ex)
            {
              Debug.WriteLine("Couldn't parse pasted xml: " + ex.ToString());
            }
          }
          else if (Clipboard.ContainsImage())
          {
            try
            {
              // get the imgage
              BitmapSource bs = Clipboard.GetImage();

              if (!Directory.Exists(Directory.GetCurrentDirectory() + "\\images"))
              {
                Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\images");
              }

              // $tss THIS IS TOTALLY WRONG
              // we need to find our app's directory instead of the currentdirectory - cause that changes all the time

              string filename = Directory.GetCurrentDirectory() +
                "\\images\\" + bs.GetHashCode().ToString() + ".png";

              // try to save it to disk
              // not very space efficient
              FileStream stream = new FileStream(filename, FileMode.Create);
              PngBitmapEncoder encoder = new PngBitmapEncoder();
              encoder.Frames.Add(BitmapFrame.Create(bs));
              encoder.Save(stream);
              stream.Close();

              Rect imageRect = new Rect(new Point(20, 20), new Size(bs.PixelWidth, bs.PixelHeight));

              // register the local file to be served
              HttpFileServer.RegisterFile(filename);
              //string remoteImageUrl = HttpFileServer.GetRemoteImageUrl(filename);
              string remoteImageUrl = filename;

              SketchRectangle wozRectangle = new SketchRectangle(imageRect, this.WozObjectRegistry, remoteImageUrl);
              this.Children.Add(wozRectangle);

              createdObjects.Add(wozRectangle.GetWozObject());

              createdUies.Add(wozRectangle);
            }
            catch (Exception ex)
            {
              Debug.WriteLine("Couldn't create image: " + ex.ToString());
            }
          }
          else if (Clipboard.ContainsText())
          {
            string text = Clipboard.GetText();

            // create a WozRectangle
            Rect rect = new Rect(15, 15, 400, 40);

            SketchText wozText = new SketchText(rect, this.WozObjectRegistry, text);
            this.Children.Add(wozText);

            createdObjects.Add(wozText.GetWozObject());

            createdUies.Add(wozText);

            //wozText.TextChanged += new TextChangedEventHandler(wozText_TextChanged);
          }
          else if (Clipboard.ContainsFileDropList())
          {

            foreach (string filename in Clipboard.GetFileDropList())
            {
              try
              {
                BitmapSource bs = new BitmapImage(new Uri(filename));

                Rect imageRect = new Rect(new Point(20, 20), new Size(Width, Height));

                // register the local file to be served
                HttpFileServer.RegisterFile(filename);
                //string remoteImageUrl = HttpFileServer.GetRemoteImageUrl(filename);
                string remoteImageUrl = filename;

                SketchRectangle wozRectangle = new SketchRectangle(imageRect, this.WozObjectRegistry, remoteImageUrl);
                this.Children.Add(wozRectangle);

                createdObjects.Add(wozRectangle.GetWozObject());

                createdUies.Add(wozRectangle);
              }
              catch (Exception ex)
              {
                Debug.WriteLine("Couldn't create image: " + ex.ToString());
              }
            }
          }


          //if (createdObjects.Count > 0 && (createdUies.Count > 0 || createdStrokes.Count > 0))
          //{
          //  SelectToolWozCommand wstc = new SelectToolWozCommand(SketchPad.CurrentInkTool, InkTools.Selector);

          //  NotifyCommandOccured(wstc);

          //  this.Select(createdStrokes, createdUies);

          //  CreateSketchCommand wccc = new CreateSketchCommand(createdObjects);

          //  NotifyCommandOccured(wccc);
          //}
        }
        catch (Exception ex)
        {
          Debug.WriteLine(ex.ToString());
        }

        // shift left
        // shift up
        double minLeft = double.MaxValue;
        double minTop = double.MaxValue;
        foreach (UIElement uie in this.Children)
        {
          if ((double)uie.GetValue(InkCanvas.LeftProperty) < minLeft)
          {
            minLeft = (double)uie.GetValue(InkCanvas.LeftProperty);
          }

          if ((double)uie.GetValue(InkCanvas.TopProperty) < minTop)
          {
            minTop = (double)uie.GetValue(InkCanvas.TopProperty);
          }
        }
        foreach (Stroke stroke in this.Strokes)
        {
          if (stroke.GetBounds().Left < minLeft)
          {
            minLeft = stroke.GetBounds().Left;
          }

          if (stroke.GetBounds().Top < minTop)
          {
            minTop = stroke.GetBounds().Top;
          }
        }

        if (minLeft < double.MaxValue && minTop < double.MaxValue)
        {
          foreach (UIElement uie in this.Children)
          {

            if (uie is ISketchObject)
            {
              //ISketchObject iSketchObject = uie as ISketchObject;

              //SketchProperty sketchProperty = iSketchObject.GetProperty(WozPropertyType.RectGeometry);

              //if (sketchProperty is RectGeometrySketchProperty)
              //{
              //  RectGeometrySketchProperty rectGeometrySketchProperty = sketchProperty as RectGeometrySketchProperty;

              //  iSketchObject.SetProperty(new RectGeometrySketchProperty(
              //    new Rect(rectGeometrySketchProperty.Rect.Left - minLeft,
              //    rectGeometrySketchProperty.Top - minTop, rectGeometrySketchProperty.Width,
              //    rectGeometrySketchProperty.Height), WozPropertyType.RectGeometry));
              //}

              uie.SetValue(InkCanvas.LeftProperty,
              (double)uie.GetValue(InkCanvas.LeftProperty) - minLeft);

              uie.SetValue(InkCanvas.TopProperty,
                (double)uie.GetValue(InkCanvas.TopProperty) - minTop);

              (uie as ISketchObject).SyncProperties();
            }
          }

          Matrix inkTransform = new Matrix();
          inkTransform.Translate(-minLeft,-minTop);

          foreach (Stroke stroke in this.Strokes)
          {
            if (stroke is ISketchObject)
            {
              stroke.Transform(inkTransform, false);
              (stroke as ISketchObject).SyncProperties();
            }
          }
        }

        // measure
        double maxWidth = 0;
        double maxHeight = 0;
        foreach (UIElement uie in this.Children)
        {
          // need to make them figure out how big they are
          uie.Measure(new Size(double.MaxValue, double.MaxValue));

          if ((double)uie.GetValue(InkCanvas.LeftProperty) >= 0 &&
            uie.DesiredSize.Width + (double)uie.GetValue(InkCanvas.LeftProperty) > maxWidth)
          {
            maxWidth = uie.DesiredSize.Width + (double)uie.GetValue(InkCanvas.LeftProperty);
          }

          if ((double)uie.GetValue(InkCanvas.TopProperty) >= 0 &&
            uie.DesiredSize.Height + (double)uie.GetValue(InkCanvas.TopProperty) > maxHeight)
          {
            maxHeight = uie.DesiredSize.Height + (double)uie.GetValue(InkCanvas.TopProperty);
          }
        }
        foreach (Stroke stroke in this.Strokes)
        {
          Rect bounds = stroke.GetBounds();

          if (bounds.Right > maxWidth)
          {
            maxWidth = bounds.Right;
          }

          if (bounds.Bottom > maxHeight)
          {
            maxHeight = bounds.Bottom;
          }
        }

        // clip
        if (maxWidth > 0 && maxHeight > 0)
        {
          this.Width = maxWidth;
          this.Height = maxHeight;
        }
      }
    }

    /// <summary>
    /// Returns a clone of this sketchpad, but with all items shifted to fit over the toReplace objects
    /// </summary>
    /// <param name="toReplace"></param>
    /// <returns></returns>
    public override SketchPad Clone(IEnumerable<SketchObject> toReplace, SketchPad container)
    {
      SketchPad sketchPad = this.Clone();

      // shift right
      // shift down
      double minLeft = double.MaxValue;
      double minTop = double.MaxValue;
      foreach (SketchObject sketchObject in toReplace)
      {
        ISketchObject iSketchObject = sketchObject.GetIWozObject(container.WozObjectRegistry);
        if (iSketchObject is UIElement)
        {
          UIElement uie = iSketchObject as UIElement;
          if ((double)uie.GetValue(InkCanvas.LeftProperty) < minLeft)
          {
            minLeft = (double)uie.GetValue(InkCanvas.LeftProperty);
          }

          if ((double)uie.GetValue(InkCanvas.TopProperty) < minTop)
          {
            minTop = (double)uie.GetValue(InkCanvas.TopProperty);
          }
        }
        else if (iSketchObject is Stroke)
        {
          Stroke stroke = iSketchObject as Stroke;
          if (stroke.GetBounds().Left < minLeft)
          {
            minLeft = stroke.GetBounds().Left;
          }

          if (stroke.GetBounds().Top < minTop)
          {
            minTop = stroke.GetBounds().Top;
          }
        }
      }

      if (minLeft < double.MaxValue && minTop < double.MaxValue)
      {
        foreach (UIElement uie in sketchPad.Children)
        {


          if (uie is ISketchObject)
          {
            //ISketchObject iSketchObject = uie as ISketchObject;

            //SketchProperty sketchProperty = iSketchObject.GetProperty(WozPropertyType.RectGeometry);

            //if (sketchProperty is RectGeometrySketchProperty)
            //{
            //  RectGeometrySketchProperty rectGeometrySketchProperty = sketchProperty as RectGeometrySketchProperty;

            //  iSketchObject.SetProperty(new RectGeometrySketchProperty(
            //    new Rect(rectGeometrySketchProperty.Rect.Left + minLeft,
            //    rectGeometrySketchProperty.Top + minTop, rectGeometrySketchProperty.Width,
            //    rectGeometrySketchProperty.Height), WozPropertyType.RectGeometry));
            //}

            uie.SetValue(InkCanvas.LeftProperty,
            (double)uie.GetValue(InkCanvas.LeftProperty) + minLeft);

            uie.SetValue(InkCanvas.TopProperty,
              (double)uie.GetValue(InkCanvas.TopProperty) + minTop);

            (uie as ISketchObject).SyncProperties();

          }
        }

        Matrix inkTransform = new Matrix();
        inkTransform.Translate(minLeft, minTop);

        foreach (Stroke stroke in sketchPad.Strokes)
        {
          if (stroke is ISketchObject)
          {
            stroke.Transform(inkTransform, false);
            (stroke as ISketchObject).SyncProperties();
          }
        }
      }

      return sketchPad;
    }

    public static ReplacementPad FromReplacementPadServerObject(ReplacementPadServerObject replacementPadServerObject)
    {
      ReplacementPad replacementPad = new ReplacementPad(false);

      replacementPad.UpdateWithReplacementPadServerObject(replacementPadServerObject);

      return replacementPad;
    }

    private void UpdateWithReplacementPadServerObject(ReplacementPadServerObject replacementPadServerObject)
    {
      this.UpdateWithSketchPadServerObject(replacementPadServerObject);
    }

    public override ServerObject GetServerObject()
    {
      return new ReplacementPadServerObject(this.ServerID);
    }
  }
}
